package com.kmproject.haifu.app.utils;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;
import com.kmproject.haifu.mvp.model.entity.resbean.SelectAddressMapBean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import timber.log.Timber;

import static java.lang.String.format;

/**
 * 谷歌定位插件（非服务方式）
 *
 * @author Kevin.Lee
 */
@SuppressLint("MissingPermission")
public class GoogleLocationUtil {
    private boolean isJustOnce = true;//仅一次定位
    private Geocoder mGeocoder;
    private Context mContext;
    @SuppressLint("StaticFieldLeak")
    private static GoogleLocationUtil locationWrap;

    private LocationManager locationManager;
    private LocationListener mLocationListener;
    private OnLocationFinishListener onLocationFinishListener;
    private OnLocationPoiListListener onLocationPoiListListener;

    public static GoogleLocationUtil getInstance(Context context) {
        if (locationWrap == null) {
            locationWrap = new GoogleLocationUtil(context.getApplicationContext());
        }
        return locationWrap;
    }

    private GoogleLocationUtil(Context context) {
        this.mContext = context;
        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        mGeocoder = new Geocoder(context);
    }

    /**
     * 设置仅定位一次（成功定位之后将会停止定位）
     *
     * @param justOnce true-只执行一次，false-不限
     */
    public GoogleLocationUtil setJustOnce(boolean justOnce) {
        isJustOnce = justOnce;
        return this;
    }

    /**
     * 这是调取Android原生定位（由{@link OnLocationFinishListener}回调定位结果）
     */
    public void startLocation() {
        Criteria criteria = new Criteria();
        // Criteria是一组筛选条件
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        //设置定位精准度
        criteria.setAltitudeRequired(false);////设置是否可以定位海拔,如果设置定位海拔，返回一定是gps
        //是否要求海拔
        criteria.setBearingRequired(true);
        //是否要求方向
        criteria.setCostAllowed(true);
        //是否要求收费
        criteria.setSpeedRequired(true);
        //是否要求速度
        criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);
        //设置电池耗电要求
        criteria.setBearingAccuracy(Criteria.ACCURACY_HIGH);
        //设置方向精确度
        criteria.setSpeedAccuracy(Criteria.ACCURACY_HIGH);
        //设置速度精确度
        criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
        //设置水平方向精确度
        criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);
        //设置垂直方向精确度

        //返回满足条件的当前设备可用的provider，第二个参数为false时返回当前设备所有provider中最符合条件的那个provider，但是不一定可用
//       locationManager.getBestProvider(criteria, true);

        if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            if (mLocationListener == null) {
                mLocationListener = new CustomLocationListener();
            }
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 2000, 10F, mLocationListener);
        }
    }

    /**
     * 调用谷歌地图开放平台的接口获取当前位置信息（由{@link OnLocationFinishListener}回调返回第一条数据作为当前位置）
     */
    @SuppressLint({"DefaultLocale", "StringFormatInTimber"})
    public void findCurrentPlace() {
        final List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.LAT_LNG, Place.Field.ADDRESS);
        FindCurrentPlaceRequest request = FindCurrentPlaceRequest.builder(placeFields).build();

        PlacesClient placesClient = Places.createClient(mContext);
        Task<FindCurrentPlaceResponse> placeResponse = placesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                FindCurrentPlaceResponse response = task.getResult();
                if (response != null) {
//                    for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
//                        Timber.i(format("Place '%s' has likelihood: %f",
//                                placeLikelihood.getPlace().getName(),
//                                placeLikelihood.getLikelihood()));
//                    }
                    SelectAddressMapBean locateCity = null;
                    if (response.getPlaceLikelihoods().size() > 0) {
                        PlaceLikelihood placeLikelihood = response.getPlaceLikelihoods().get(0);
                        Place place = placeLikelihood.getPlace();

                        locateCity = new SelectAddressMapBean(place.getName(), place.getAddress(), String.valueOf(Objects.requireNonNull(place.getLatLng()).latitude), String.valueOf(Objects.requireNonNull(place.getLatLng()).longitude));
                    }
                    if (onLocationFinishListener != null && locateCity != null) {
                        String sb = locateCity.getTitle() +
                                "\n" +
                                locateCity.getDetileAddress() +
                                "\n" +
                                locateCity.getLat() +
                                "\n" +
                                locateCity.getLgt();
                        Timber.i(sb);
                        onLocationFinishListener.locationFinish(locateCity);
                        if (isJustOnce) {
                            stopLocation();
                        }
                    }
                } else {
                    Timber.e("Place not found");
                    if (onLocationFinishListener != null) {
                        onLocationFinishListener.fail("Place not found");
                    }
                }
            } else {
                Exception exception = task.getException();
                if (exception instanceof ApiException) {
                    ApiException apiException = (ApiException) exception;
                    Timber.e("Place not found: %s", apiException.getStatusCode());
                    if (onLocationFinishListener != null) {
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.append(apiException.getStatusCode());
                        if (apiException.getMessage() != null) {
                            stringBuilder.append(apiException.getMessage());
                        }
                        onLocationFinishListener.fail("Place not found: " + stringBuilder.toString());
                    }
                } else {
                    Timber.e("Place not found: Location is Exception");
                    if (onLocationFinishListener != null) {
                        onLocationFinishListener.fail("Location is Exception");
                    }
                }
            }
        });
    }

    /**
     * 获取当前位置周边可能的位置信息列表(由{@link OnLocationPoiListListener}回调结果信息)
     */
    @SuppressLint({"DefaultLocale", "StringFormatInTimber"})
    public void getPeripheryPossibleLocation() {
        final List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.LAT_LNG, Place.Field.ADDRESS);
        FindCurrentPlaceRequest request = FindCurrentPlaceRequest.builder(placeFields).build();

        PlacesClient placesClient = Places.createClient(mContext);
        Task<FindCurrentPlaceResponse> placeResponse = placesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(task -> {
            if (task.isSuccessful()) {
                FindCurrentPlaceResponse response = task.getResult();
                if (response != null) {
                    List<SelectAddressMapBean> poiList = new ArrayList<>();
                    SelectAddressMapBean poiInfo;
                    for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                        Timber.i(format("Place '%s' has likelihood: %f",
                                placeLikelihood.getPlace().getName(),
                                placeLikelihood.getLikelihood()));
                        poiInfo = new SelectAddressMapBean();
                        poiInfo.setType(0);
                        poiInfo.setTitle(placeLikelihood.getPlace().getName());
                        if (placeLikelihood.getPlace().getLatLng() != null) {
                            poiInfo.setLat(String.valueOf(placeLikelihood.getPlace().getLatLng().latitude));
                            poiInfo.setLgt(String.valueOf(placeLikelihood.getPlace().getLatLng().longitude));
                        }
                        poiInfo.setDetileAddress(placeLikelihood.getPlace().getAddress());
                        poiList.add(poiInfo);
                    }
                    if (onLocationPoiListListener != null) {
                        onLocationPoiListListener.poiList(poiList);
                        if (isJustOnce) {
                            stopLocation();
                        }
                    }
                } else {
                    Timber.e("Place not found");
                    if (onLocationPoiListListener != null) {
                        onLocationPoiListListener.fail("Place not found");
                    }
                }
            } else {
                Exception exception = task.getException();
                if (exception instanceof ApiException) {
                    ApiException apiException = (ApiException) exception;
                    Timber.e("Place not found: %s", apiException.getStatusCode());
                    if (onLocationPoiListListener != null) {
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.append(apiException.getStatusCode());
                        if (apiException.getMessage() != null) {
                            stringBuilder.append(apiException.getMessage());
                        }
                        onLocationPoiListListener.fail("Place not found: " + stringBuilder.toString());
                    }
                } else {
                    Timber.e("Place not found: Location is Exception");
                    if (onLocationPoiListListener != null) {
                        onLocationPoiListListener.fail("Location is Exception");
                    }
                }
            }
        });
    }

    private void getAddress(Location location) {
        List<Address> addressList = null;
        try {
            addressList = mGeocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 5);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //第一个为当前位置信息，其他的为可能的位置推荐
        if (addressList != null && addressList.size() > 0) {
            Address address = addressList.get(0);
            String sb = address.getCountryCode() +
                    "\n" +
                    address.getCountryName() +
                    "\n" +
                    address.getAdminArea() +
                    "\n" +
                    address.getLocality() +
                    "\n" +
                    address.getSubLocality() +
                    "\n" +
                    address.getAddressLine(0);
            Timber.i(sb);

            SelectAddressMapBean locateCity;
            if (address.getCountryCode().equalsIgnoreCase("cn")) {
//                double[] r = GPSUtil.gps84_To_Gcj02(address.getLatitude(), address.getLongitude());
//                locateCity = new SelectAddressMapBean(address.getFeatureName(), address.getAddressLine(0), String.valueOf(r[0]), String.valueOf(r[1]));
                locateCity = new SelectAddressMapBean(address.getFeatureName(), address.getAddressLine(0), String.valueOf(address.getLatitude()), String.valueOf(address.getLongitude()));
            } else {
                locateCity = new SelectAddressMapBean(address.getFeatureName(), address.getAddressLine(0), String.valueOf(address.getLatitude()), String.valueOf(address.getLongitude()));
            }
//            RestaurantApplication.locateCity = locateCity;
            if (onLocationFinishListener != null) {
                onLocationFinishListener.locationFinish(locateCity);
                if (isJustOnce) {
                    stopLocation();
                }
            }
        }
    }

    private class CustomLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            if (location != null) {
                getAddress(location);
            } else {
                locationFail();
            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    }

    private void locationFail() {
        Timber.i("Location fails");
        //失败则使用Gps尝试定位一次
        if (onLocationFinishListener != null) {
            onLocationFinishListener.fail("Location fails");
        }
    }

    public interface OnLocationPoiListListener {
        void poiList(List<SelectAddressMapBean> poiList);

        void fail(String message);
    }

    public GoogleLocationUtil setOnLocationPoiListListener(OnLocationPoiListListener onLocationPoiListListener) {
        this.onLocationPoiListListener = onLocationPoiListListener;
        return this;
    }


    public interface OnLocationFinishListener {
        void locationFinish(SelectAddressMapBean locateCity);

        void fail(String message);
    }

    public GoogleLocationUtil setOnLocationFinishListener(OnLocationFinishListener onLocationFinishListener) {
        this.onLocationFinishListener = onLocationFinishListener;
        return this;
    }

    public void stopLocation() {
        if (mLocationListener != null) {
            locationManager.removeUpdates(mLocationListener);
        }
        onLocationFinishListener = null;
        onLocationPoiListListener = null;
        locationWrap = null;
    }
}
